import UIKit

var str = "Hello, playground"

//协议：方法、属性、或者一个功能的的声明（没有实现）

//协议可以被类，结构体，枚举使用而实现具体的方法
//任何满足协议需求的类型，被称为尊从该协议

protocol AProtocol {
    
}

protocol BProtocol {
    
}

//一个结构体或者类尊从多个协议，用逗号分隔开

struct AStruct : AProtocol,BProtocol {
    
    
}

class Name {
    
}
//超类Name写在协议AProtocol之前，常规操作
class GivenName : Name ,AProtocol ,BProtocol {
    
    
}

//结构体和枚举不能继承，但是结构体和枚举能够遵从协议，达到一个继承的目的，而协议的遵从，就类似于只要我遵从的协议的一小块功能。这样灵活一点

//属性协议，用的最多了

//要求实现getter方法（setter可选）,属性必须定义为变量

//属性协议
protocol FileAccessPriority {
    var readOnly : Bool { get }
    var readWrite : Bool {get set}
    
    
}


protocol AccessUrl {
    static var link: String { get }
}


protocol FullName {
    var fName : String {get}
    var gName : String {get}
}

struct Student : FullName {
    var fName: String
    var gName: String
    
}

struct Teacher : FullName {
    var fName: String
    var gName: String
}

var student1 = Student(fName: "小明", gName: "王")
student1.fName
student1.gName

 class SSomeBody : FullName {
    
    var title:String?
    var name: String
    
    init(title: String?, name:String) {
        self.title = title
        self.name = name
    }
    
    var gName: String {
        return name
    }
    var fName: String {
        return title ?? "无名人士"
    }
    
    var desc : String {
        return self.fName + self.gName
    }
    
    
}

var sombody1 = SSomeBody(title: "大帝", name: "亚历山大")
sombody1.gName
sombody1.fName

var nobody1 = SSomeBody(title: nil, name: "小波")
nobody1.fName
nobody1.gName


//方法协议

//让类，结构体，枚举分解为更小的组合

//类型方法写协议 前缀总是static

protocol AMethod {
    static func foo()
}


class A :AMethod {
//    不可被继承
    static func foo() {
        print("aaa aaa ")
    }
//    可被继承
//    class func foo() {
//        print("bbb")
//    }
}



import Foundation
//实例方法协议
//产生随机数
protocol RandomGeneratable {
    func randomNumber() -> Int
}

struct RandomNumber : RandomGeneratable {
    func randomNumber() -> Int {
        return Int(arc4random())
    }
}

let random1 = RandomNumber()
random1.randomNumber()


struct RnadomNumberInSix : RandomGeneratable {
    func randomNumber() -> Int {
        return Int(arc4random()) % 6 + 1
    }
}

let random2 = RnadomNumberInSix()
random2.randomNumber()



//结构体，枚举 编译方法协议 需要更改的时候需要添加mutating


protocol Switchable {
  mutating func onoff()
}

enum MySwitch : Switchable {
    case on,off
    mutating func onoff() {
        switch self {
        case .off:
            self = .on
        default:
            self = .off
        }
    }
}

//构造方法协议

//可以要求遵从者实现指定的构造方法，实现时用required init,编译时候会提示添加，无需手动添加required,不常用

protocol C {
    init(c: Int)
}

struct D : C {
    init(c: Int) {
        
    }
}

class E : C {
    required init(c: Int) {
        
    }
    
    
}


//协议作为类型使用***
//可用于参数类型，返回类型，变量，常量，属性，集合类型中的元素类型

class MyRandomNumber : RandomGeneratable {
    func randomNumber() -> Int {
        return Int(arc4random()) % 10 + 1
    }
}

struct Dice {
    var sides : Int
    var randomNumber : RandomGeneratable
    
    func play() -> Int {
        return self.randomNumber.randomNumber() % sides + 1
    }
    
}

let aDice = Dice(sides: 99, randomNumber: RandomNumber())

aDice.play()


//协议作为代理使用

//协议作为代理：代理是一种常见的设计模式，可以让类或者结构体把一部分职责，指派给非同类的实例去承担。

//要寻求代理，可以通过定义一个协议，打包要实现的职责在协议中。

//该代理协议的遵从者，就可以实现这些打包的职责

//代理在iOS开发中，一般可以用于响应特定的操作，或从外部数据源取回数据，但无需了解是何种数据源

struct Role {
    var name : String
}

protocol Player {
    var role : Role {get}
    mutating func Play()
}

protocol GameDelegate {
    func start(with player : Player) -> Int
    func rolePK(with player : Player, armed :Bool) -> Int
    func end(with player : Player ) -> Int
}

struct GameAgent : GameDelegate {
    func start(with player: Player) -> Int {
        print(player.role.name, "开始进入游戏，获得经验2000")
        return 2000
    }
    
    func rolePK(with player: Player, armed: Bool) -> Int {
        if armed {
            print(player.role.name,"开始PK，您有武器，获得经验5000")
            return 5000
        }else {
            print(player.role.name,"开始pk","您没有武器，获得经验2500")
            return 2500
        }
    }
    
    func end(with player: Player) -> Int {
        print(player.role.name,"正常退出，获得经验1000")
        return 1000
    }
    
}

struct MirPlayer : Player {
    var exp : Int
    var gameAgent : GameAgent?
    
    var role: Role
    mutating func Play() {
        if let gameAgent = gameAgent {
            print("您使用了代玩")
            exp += gameAgent.start(with: self)
            exp += gameAgent.rolePK(with: self, armed: true)
            exp += gameAgent.end(with: self)
        }else {
            print("您没有使用，不能自动升级")
        }
    }
    
}

let role = Role(name: "小波")
var playerN = MirPlayer(exp: 0, gameAgent: nil, role: role)
playerN.Play()

let role2 = Role(name: "土豪玩家")
let agent = GameAgent()
var palyerE = MirPlayer(exp: 0, gameAgent: agent, role: role2)
palyerE.Play()

//协议的扩展和协议的约束

//协议扩展：给无源码的添加协议（给系统类添加协议）

let a = 1

protocol ShowHint {
    func hint() -> String
}

extension Int : ShowHint {
    func hint() -> String {
        return "整数：\(self)"
    }
}

a.hint()
(-1).hint()


//如果一个类型预遵从了协议，可以直接扩展协议

struct Lesson {
    var name : String
    var description : String {
        return "课程名是：" + name
    }
}

1.description

//extension Lesson : CustomStringConvertible{
//    var description: String {
//        retu
//    }
//}

//扩展约束：可以在扩展协议的同时，加上限定条件.where语句
extension ShowHint where Self: CustomStringConvertible {
    func hint2() -> String {
        return "我是一个能显示成字符串的类型" + self.description
    }
}
1.hint2()


//集合类型Collection也是一种协议Iterator.Element指代其中的元素

let array = [1,2,3,4,5]
extension Collection where Iterator.Element :CustomStringConvertible {
    func newDesc() -> String {
        let itemAsText = self.map{ $0.description }
        return "该集合类型元素数目是\(self.count),元素的值依次是" + itemAsText.joined(separator: ",")
    }
}

array.newDesc()
print(array)


//协议集合类型，因为协议可以作为类型使用，可以把遵从相同协议的实例放到一个协议类型的数组

let arry:[CustomStringConvertible] = [1,2,3,"hha"]
for element in arry {
    print(element)
}


//协议继承和默认实现

//class不能多重继承，结构体进行协议扩展，相当于多重继承

protocol MyPrintable : CustomStringConvertible, CustomPlaygroundDisplayConvertible {

}
//
struct MyContent {
    var text : String
    var mycustomtext : String

}

extension MyPrintable {
   var playgroundDescription: Any {
        return "PlayfroundQuickLook is departure"
    }
}


//提供默认实现，不需要每个继承他的结构体和枚举都具体实现


extension MyContent : MyPrintable {
    
    var playgroundDescription: Any {
        return self.mycustomtext
    }
    
   
    var description: String {
        return self.text
    }
}


let mycontent1 = MyContent(text: "内容", mycustomtext: "保留文字")
mycontent1.description

//swift中协议继承，提倡多协议组合的做法


//类专用协议 多加个关键字class 用的少
protocol OnlyForClass : class, CustomStringConvertible, CustomPlaygroundDisplayConvertible {
    
}

class MyText : OnlyForClass {
    
    var description: String {
        return "aaa"
    }
    
    var playgroundDescription: Any {
        return "bbbb"
    }
    
    
}
//报错，只能由class来继承
//struct : MyStruct : OnlyForClass
//{
//
//}

//协议组合 协议1 & 协议2 & 协议3

protocol Ageable {
    var age : Int {get}
}

protocol Nameable {
    var name : String { get }
}

struct StudentT : Ageable,Nameable {
    var age : Int
    var name : String
}

struct TeacherT : Ageable,Nameable {
    var age : Int
    var name : String
    var title : String
    
}

func wish(someone : Ageable & Nameable) {
    print("祝",someone.name,someone.age,"岁生日快乐！")
}

let studentt1 = StudentT(age: 10, name: "Tom")
let teachert1 = TeacherT(age: 30, name: "Bob", title: "Professor")

wish(someone: studentt1)
wish(someone: teachert1)

//没有很严格的意义，灵活性强，拆小功能，大的功能用小的功能组合


//协议的检查和转换 使用is和as类型操作符来检查协议遵从与否，或转换成特定的协议

protocol Slogan {
    var desc: String { get }
}

protocol Coder : Slogan {
    var name:String { get }
    
}

struct JavaCode : Coder {
    
    var name: String
    var desc: String {
        return "我会Java我流弊"
    }
    
    
}

struct JScoder : Coder {
    var name: String
    var desc: String {
        return "我会JS我很潮"
    }
}

struct NewBie {
    var name : String
}

let java1 = JavaCode(name: "小牧")
let js1 = JScoder(name: "小可")
let newbie1 = NewBie(name: "小波")
let coders = [java1,js1,newbie1] as [Any]
for coder in coders {
    if let coder = coder as? Coder {
        print(coder.name,coder.desc)
    }else {
        print("你不是一个程序员")
    }
    
    if let newbie = coder as? NewBie {
        print("你是菜鸟~",newbie.name)
    }
}
